<?php

namespace Bete\Foundation;

use Exception;

class ProviderRepository
{
    protected $app;

    public function __construct($app)
    {
        $this->app = $app;
    }

    public function load()
    {
        $manifest = $this->loadManifest();

        foreach ($manifest['eager'] as $provider) {
            $this->app->register($this->createProvider($provider));
        }

        $this->app->addDeferredServices($manifest['deferred']);
    }

    public function loadManifest()
    {
        $this->manifestPath = $this->app['path.compiled'] . '/services.php';
        $providers = $this->app->config['app']['providers'];

        $manifest = null;
        if (file_exists($this->manifestPath)) {
            $manifest = require($this->manifestPath);

            if (!is_array($manifest)) {
                throw new Exception("is not array");
            }
        }

        if (is_null($manifest) || $manifest['providers'] != $providers) {
            $manifest = $this->compileManifest($providers);
        }

        $this->writeManifest($manifest);

        return $manifest;
    }

    protected function writeManifest($manifest)
    {
        $content = '<?php return ' . var_export($manifest, true) . ';';
        
        if (!@file_put_contents($this->manifestPath, $content)) {
            throw new Exception('Fail to write ' . $this->manifestPath . '.');
        }
    }

    protected function compileManifest($providers)
    {
        $manifest = ['providers' => $providers, 'eager' => [], 'deferred' => []];

        foreach ($providers as $provider) {
            $instance = $this->createProvider($provider);

            if ($instance->isDeferred()) {
                foreach ($instance->providers() as $service) {
                    $manifest['deferred'][$service] = $provider;
                }
            } else {
                $manifest['eager'][] = $provider;
            }
        }

        return $manifest;
    }

    public function loadProviders()
    {
        $providers = $this->app->config['app.providers'];
        foreach ($providers as $provider) {
            $this->app->register($this->createProvider($provider));
        }
    }

    public function createProvider($provider)
    {
        return new $provider($this->app);
    }
}
